namespace classifier_test
{

namespace high_order
{

class validation_classifier;

class validation_dataset : public virtual virtual_object, private noncopyable
{
public:
	validation_dataset();
	validation_dataset(const validation_dataset& Val);
	virtual smart_ptr<validation_dataset> clone() const = 0;
	virtual int size() const = 0;
	virtual void build(subarray<const record* const> Data) = 0;
	virtual void add(validation_dataset* Dataset) = 0;
	virtual smart_ptr<validation_classifier> train(classifier* BaseClassifier) = 0;
};

class validation_classifier : public virtual virtual_object, private noncopyable
{
public:
	validation_classifier();
	validation_classifier(const validation_classifier& Val);
	virtual smart_ptr<validation_classifier> clone() const = 0;
	virtual double test_error(validation_dataset* Dataset) const = 0;
	virtual void test_results(validation_dataset* Dataset,  vector<discr_value>& Results) const = 0;
	virtual smart_ptr<classifier> get_ensemble_classifier() const = 0;
};

class holdout_validation_dataset : public validation_dataset
{
	friend class holdout_validation_classifier;
public:
	holdout_validation_dataset();
	holdout_validation_dataset(const holdout_validation_dataset& Val);
	holdout_validation_dataset(subarray<const record* const> Data);
	smart_ptr<validation_dataset> clone() const;
	int size() const;

	void build(subarray<const record* const> Data);
	void add(validation_dataset* Dataset);
	smart_ptr<validation_classifier> train(classifier* BaseClassifier);

private:
	vector<const record*> Trains, Tests;
};

class holdout_validation_classifier : public validation_classifier
{
	friend class holdout_validation_dataset;
public:
	holdout_validation_classifier();
	holdout_validation_classifier(const holdout_validation_classifier& Val);
	smart_ptr<validation_classifier> clone() const;
	double test_error(validation_dataset* Dataset) const;
	void test_results(validation_dataset* Dataset,  vector<discr_value>& Results) const;
	smart_ptr<classifier> get_ensemble_classifier() const;

private:
	smart_ptr<classifier> Classifier;
};

class cross_validation_dataset : public validation_dataset
{
	friend class cross_validation_classifier;
public:
	cross_validation_dataset(int SetGroupCount = 0);
	cross_validation_dataset(const cross_validation_dataset& Val);
	cross_validation_dataset(int SetGroupCount, subarray<const record* const> SetData);
	smart_ptr<validation_dataset> clone() const;
	int size() const;
	int get_group_count() const;
	void set_group_count(int Val);

	void build(subarray<const record* const> SetData);
	void add(validation_dataset* Dataset);
	smart_ptr<validation_classifier> train(classifier* BaseClassifier);

private:
	int GroupCount;
	int DataCount;
	vector<vector<const record*> > Data;
};

class cross_validation_classifier : public validation_classifier
{
	friend class cross_validation_dataset;
public:
	cross_validation_classifier();
	cross_validation_classifier(const cross_validation_classifier& Val);
	smart_ptr<validation_classifier> clone() const;
	double test_error(validation_dataset* Dataset) const;
	void test_results(validation_dataset* Dataset,  vector<discr_value>& Results) const;
	smart_ptr<classifier> get_ensemble_classifier() const;

private:
	vector<smart_ptr<classifier> > Classifiers;
};

}

}
